package com.szlanyou.thirdsdk.retrofit.util;

import android.annotation.SuppressLint;
import android.util.Log;

import androidx.lifecycle.ViewModel;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

/**
 * @author 陈章
 */
public class ReflectManger {

    public static Class getClassByName(String pkg) throws ClassNotFoundException {
        return ReflectManger.class.getClassLoader().loadClass(pkg);
    }

    public static Object invokeMethod(Class clazz, Object instance, String methodName, Class[] parms, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = clazz.getDeclaredMethod(methodName, parms);
        method.setAccessible(true);
        return method.invoke(instance, args);
    }

    public static Object getField(Class clazz, Object instance, String fieldName)  {
        try {
            Field field =  clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(instance);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void setField(Class clazz, Object instance, String fieldName,Object fieldValue)  {
        try {
            Field field =  clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(instance,fieldValue);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取泛型
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> Class<T> getGeneric(Object obj){
        //根据泛型获取字节码
        //子类的构造方法会默认调用父类空参  super(), 所以this代表子类对象
        //子类字节码对象
        Class childClazz = obj.getClass();


        //得到父类的字节码BaseDaoImpl的字节码 ， 这份字节码上带有泛型数据
        /**
         * 虽然这个方法，返回值说的是Type ，
         * 但是其实返回的是ParameterizedType的实现类类型。
         * 所以我们使用ParameterizedTypeImpl接口来接收。
         */
        ParameterizedType genericSuperclass = (ParameterizedType) childClazz.getGenericSuperclass();
        //父类没有写任何的泛型
        Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
        if(actualTypeArguments == null || actualTypeArguments.length == 0){
            return null;
        }
        //获取这样可以得到泛型了
        //因为泛型可能不止一个,所以返回的是数组,所以我们取第一个,
        Type actualTypeArgument1 = actualTypeArguments[0];

        //当父类没有指定具体类型时，无法获取Class，也就不需要创建ViewModel了。
        if(actualTypeArgument1 instanceof TypeVariable){
            TypeVariable[] typeParameters = childClazz.getTypeParameters();
            if(typeParameters != null && typeParameters.length > 0){
                //当前类的泛型仍然是T
                if(typeParameters[0] instanceof TypeVariable){
                    return null;
                }
                return (Class<T>) typeParameters[0].getClass();
            }
            return null;
        }else{
            Class<T> actualTypeArgument = (Class<T>) actualTypeArgument1;
            if(actualTypeArgument == ViewModel.class){
                return null;
            }
            return actualTypeArgument;
        }
    }
}